﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using eJack.Utility.Entity;

namespace eJack.Mortgage.Tool
{
	/// <summary>
	/// Interaction logic for PaymentScheduleWindow.xaml
	/// </summary>
	public partial class PaymentScheduleWindow : Window
	{
		public PaymentScheduleWindow()
		{
			InitializeComponent();
		}

		private eLanguage Lang { get; set; }

		private float LoanAmount { get; set; }
		private float MonthPayment { get; set; }
		private float ExtraPayment { get; set; }
		private float YearRate { get; set; }
		private float MonthRate { get; set; }
		private int TermYear { get; set; }
		private int TermMonth { get; set; }

		private DateTime LoanDate { get; set; }

		private float TotalPayment { get; set; }
		private float TotalInterest { get; set; }

		private List<iMonthMortgageData> Mortgages { get; set; }
		private Dictionary<int, List<MortgageItemControl>> dicPages;

		public PaymentScheduleWindow(float floan, float fpayment, float fextra, float frate, float fterm, DateTime dtloan, eLanguage elang)
			: this()
		{
			this.setLanguage(elang);

			this.LoanAmount = floan;
			this.MonthPayment = fpayment;
			this.ExtraPayment = fextra;
			this.YearRate = frate;
			this.TermYear = (int)fterm;
			this.TermMonth = 12 * this.TermYear;
			this.LoanDate = dtloan;

			this.Mortgages = new List<iMonthMortgageData>();
			this.PageSize = 12;

			this.doCalculate();
			this.doUpdateBasic();
			this.doShowSchedule();
		}

		private void setLanguage(eLanguage elang)
		{
			this.Lang = elang;

			if (this.Lang == eLanguage.Chinese)
			{
				this.Title = "还款时间表";
				this.ps_summary.Text = "总算";
				this.ps_rate.Content = "利息";
				this.ps_term.Content = "年期";
				this.ps_loan.Content = "贷款总额";
				this.ps_extra.Content = "多付";
				this.ps_payment.Content = "预还款额";

				this.ps_schedule.Text = "还款时间";
				this.ps_s_month.Content = "月";
				this.ps_s_date.Content = "日期";
				this.ps_s_principal.Content = "本金";
				this.ps_s_interest.Content = "利息";
				this.ps_s_balance.Content = "贷款余额";

				this.tbFirst.Text = "始页";
				this.tbPrevious.Text = "上页";
				this.tbNext.Text = "下页";
				this.tbLastCount.Text = "末页";
			}
		}

		private void doCalculate()
		{
			this.MonthRate = this.YearRate / (12.0f * 100);

			// total payment
			// (float)(this.LoanAmount * ((this.TermMonth * this.MonthRate - 1.0f) * Math.Pow(1.0f + this.MonthRate, this.TermMonth) + 1.0f) / (Math.Pow(1.0f + this.MonthRate, this.TermMonth) - 1));
			this.TotalPayment = this.MonthPayment * this.TermMonth;

			// total interest
			this.TotalInterest = this.TotalPayment - this.LoanAmount;
		}

		private void doUpdateBasic()
		{
			this.txtRate.Content = string.Format("{0}%", this.YearRate);
			this.txtTerm.Content = string.Format("{0} {1}", this.TermYear, this.Lang == eLanguage.English ? "yrs" : "年");
			this.txtLoan.Content = this.LoanAmount.ToString("C");
			this.txtExtra.Content = this.ExtraPayment.ToString("C");
			this.txtMonthlyPayment.Content = this.MonthPayment.ToString("C");

			this.tbTotalPay.Text = string.Format("T: {0}  ", this.TotalPayment.ToString("C"));
			this.tbTotalInterest.Text = string.Format("I: {0}  ", this.TotalInterest.ToString("C"));
		}

		private void doShowSchedule()
		{
			int imonth_total = this.TermYear * 12;

			if (this.ExtraPayment <= 0)
			{
				for (int imonth = 1; imonth <= imonth_total; imonth++)
				{
					string smonth_date = (imonth > 1 ? this.LoanDate.AddMonths(imonth - 1) : this.LoanDate).ToString("yy-MM-dd");
					// A Loan, B Total Month, C Rate, X Payment

					float fRate_Month = this.MonthRate; // this.YearRate / (12.0f * 100);

					// balance
					// A×［（1＋C）ˆB－（1＋C）ˆn］／（（1＋C）ˆB－1）
					float fbalance = (float)(this.LoanAmount * (Math.Pow((1.0f + fRate_Month), imonth_total) - Math.Pow((1.0f + fRate_Month), imonth)) / (Math.Pow((1.0f + fRate_Month), imonth_total) - 1.0f));

					// ineterst
					// A×C×［（1十C）ˆB－（1＋C）ˆ（n－1）］／（（1＋C）ˆB－1）
					float fmonth_ineterst = (float)(this.LoanAmount * fRate_Month * (Math.Pow((1.0f + fRate_Month), imonth_total) - Math.Pow((1.0f + fRate_Month), imonth - 1)) / (Math.Pow((1.0f + fRate_Month), imonth_total) - 1.0f));

					// payment
					float fmonth_principal = this.MonthPayment - fmonth_ineterst + this.ExtraPayment;

					var im = new iMonthMortgageData()
					{
						Month = imonth,
						LoanDate = smonth_date,
						MonthPrincipal = fmonth_principal,
						MonthInterest = fmonth_ineterst,
						Balance = fbalance
					};

					Mortgages.Add(im);
				}
			}
			else
			{
				var dics = new Dictionary<int, iMonthMortgageData>();
				bool isend = false;
				for (int imonth = 1; imonth <= imonth_total; imonth++)
				{
					string smonth_date = (imonth > 1 ? this.LoanDate.AddMonths(imonth - 1) : this.LoanDate).ToString("yy-MM-dd");

					float fcurrentloan = (imonth == 1 ? this.LoanAmount : dics[imonth - 1].Balance);
					float finterest_month = fcurrentloan * this.MonthRate;
					float fprincipal_month = this.MonthPayment - finterest_month + this.ExtraPayment;
					if (fprincipal_month > fcurrentloan) { fprincipal_month = fcurrentloan; }
					float fbalance = fcurrentloan - fprincipal_month;

					if (fbalance <= 0.0f)
					{
						fbalance = 0.0f;
						isend = true;
					}

					var im = new iMonthMortgageData()
					{
						Month = imonth,
						LoanDate = smonth_date,
						MonthPrincipal = fprincipal_month,
						MonthInterest = finterest_month,
						Balance = fbalance
					};

					dics.Add(imonth, im);
					Mortgages.Add(im);

					if (isend) { break; }
				}

				try
				{
					float ftotal = this.LoanAmount;
					float finterest = 0.0f;

					foreach (var item in dics)
					{
						ftotal = ftotal + item.Value.MonthInterest;
						finterest = finterest + item.Value.MonthInterest;
					}

					this.tbTotalPay2.Text = string.Format("T: {0}  ", ftotal.ToString("C"));
					this.tbTotalInterest2.Text = string.Format("I: {0}  ", finterest.ToString("C"));
					this.spExtra.Visibility = System.Windows.Visibility.Visible;
				}
				catch { }
			}

			int itotal = Mortgages.Count;
			int ipage_count = itotal / this.PageSize;
			int ipage_more = itotal % this.PageSize;
			this.PageCount = ipage_more > 0 ? ipage_count + 1 : ipage_count;
			this.tbLastCount.Text = string.Format("{0} ({1})  ", (this.Lang == eLanguage.English ? "Last" : "末页"), this.PageCount);
			this.GoPage(1);
		}

		private int CurrentPage { get; set; }
		private int PageCount { get; set; }
		private int PageSize { get; set; }

		private void GoPage(int ipage_index)
		{
			if (null != Mortgages && Mortgages.Count > 0)
			{
				if (ipage_index < 1) { ipage_index = 1; }
				if (ipage_index > this.PageCount) { ipage_index = this.PageCount; }

				if (null == dicPages) { dicPages = new Dictionary<int, List<MortgageItemControl>>(); }

				if (!dicPages.ContainsKey(ipage_index))
				{
					var items = Mortgages.Skip((ipage_index - 1) * this.PageSize).Take(this.PageSize).ToList();
					if (null != items && items.Count > 0)
					{
						var iyt = new iYearMortgageData()
						{
							Year = ipage_index,
							YearPrincipal = 0.0f,
							YearInterest = 0.0f,
							Balance = 0.0f + items[items.Count - 1].Balance
						};
						var item_controls = new List<MortgageItemControl>();
						foreach (var item in items)
						{
							iyt.YearPrincipal = iyt.YearPrincipal + item.MonthPrincipal;
							iyt.YearInterest = iyt.YearInterest + item.MonthInterest;

							var mic = new MortgageItemControl();
							mic.SetData(item, this.Lang);
							item_controls.Add(mic);
						}

						var year_mic = new MortgageItemControl();
						year_mic.SetData(iyt, this.Lang);
						item_controls.Add(year_mic);

						dicPages.Add(ipage_index, item_controls);
					}
				}

				if (dicPages.ContainsKey(ipage_index))
				{
					var ePageItems = dicPages[ipage_index];
					if (null != ePageItems)
					{
						this.page.Children.Clear();
						foreach (var item in ePageItems)
						{
							if (null != item)
							{
								this.page.Children.Add(item);
							}
						}
					}
				}

				if (ipage_index == 1)
				{
					this.tbFirst.IsEnabled = false;
					this.tbPrevious.IsEnabled = false;

					this.tbFirst.Foreground = new SolidColorBrush(Colors.Gray);
					this.tbPrevious.Foreground = new SolidColorBrush(Colors.Gray);
				}
				else
				{
					this.tbFirst.IsEnabled = true;
					this.tbPrevious.IsEnabled = true;

					this.tbFirst.Foreground = new SolidColorBrush(Colors.Red);
					this.tbPrevious.Foreground = new SolidColorBrush(Colors.Red);
				}

				if (ipage_index == this.PageCount)
				{
					this.tbLastCount.IsEnabled = false;
					this.tbNext.IsEnabled = false;

					this.tbLastCount.Foreground = new SolidColorBrush(Colors.Gray);
					this.tbNext.Foreground = new SolidColorBrush(Colors.Gray);
				}
				else
				{
					this.tbLastCount.IsEnabled = true;
					this.tbNext.IsEnabled = true;

					this.tbLastCount.Foreground = new SolidColorBrush(Colors.Red);
					this.tbNext.Foreground = new SolidColorBrush(Colors.Red);
				}

				this.CurrentPage = ipage_index;
			}
		}

		private void OnTextBlock_MouseDown(object sender, MouseButtonEventArgs e)
		{
			var tb = sender as TextBlock;
			if (null != tb)
			{
				var btnName = tb.Tag.ToString();
				var ipage_index = 1;
				if (btnName.Equals("first", StringComparison.OrdinalIgnoreCase))
				{
					ipage_index = 1;
				}
				else if (btnName.Equals("last", StringComparison.OrdinalIgnoreCase))
				{
					ipage_index = this.PageCount;
				}
				else if (btnName.Equals("previous", StringComparison.OrdinalIgnoreCase))
				{
					ipage_index = this.CurrentPage - 1;
				}
				else if (btnName.Equals("next", StringComparison.OrdinalIgnoreCase))
				{
					ipage_index = this.CurrentPage + 1;
				}

				this.GoPage(ipage_index);
			}
		}
	}
}
